var uuid = require('node-uuid');
var util = require('util');
var Schema = require('jugglingdb').Schema;
var schemas = require('./schemas').schemas;

var DEFAULT_UID = '0000000000';

var schema = schemas[process.env.NODE_ENV];

var Player = schema.define('Player', {
  remoteId:       { 'type': String, 'length': 255 },
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  name:           { 'type': String, 'length': 255 },
  online:         { 'type': Boolean, 'default': false },
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var Game = schema.define('Game', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  session:        { 'type': Number, 'default': 0 },
  status:         { 'type': String, 'length': 16 },
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var GamePlayer = schema.define('GamePlayer', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  online:         { 'type': Boolean, 'default': false },
  status:         { 'type': String, 'length': 16, 'default': 'observer' },
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var Play = schema.define('Play', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  type:           { 'type': String },
  session:        { 'type': Number, 'default': 0 },
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var PlayerMetadata = schema.define('PlayerMetadata', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  key:            { 'type': String, 'index': true },
  value:          { 'type': Schema.Text },
  system:         { 'type': Boolean, 'default': false},
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var GameMetadata = schema.define('GameMetadata', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  key:            { 'type': String, 'index': true },
  value:          { 'type': Schema.Text },
  system:         { 'type': Boolean, 'default': false},
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var GamePlayerMetadata = schema.define('GamePlayerMetadata', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  key:            { 'type': String, 'index': true },
  value:          { 'type': Schema.Text },
  system:         { 'type': Boolean, 'default': false},
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

var PlayMetadata = schema.define('PlayMetadata', {
  pk:             { 'type': String, 'length': 64, 'default': DEFAULT_UID, 'index': true},
  key:            { 'type': String, 'index': true },
  value:          { 'type': Schema.Text },
  system:         { 'type': Boolean, 'default': false},
  creationTime:   { 'type': Date },
  lastUpdateTime: { 'type': Date },
});

Player.hasMany(PlayerMetadata, {as: 'metadata', foreignKey: 'playerId'});
Game.hasMany(GameMetadata, {as: 'metadata', foreignKey: 'gameId'});
Play.hasMany(PlayMetadata, {as: 'metadata', foreignKey: 'playId'});
GamePlayer.hasMany(GamePlayerMetadata, {as: 'metadata', foreignKey: 'gamePlayerId'});
Game.hasMany(GamePlayerMetadata, {as: 'gamePlayerMetadata', foreignKey: 'gameId'});

PlayerMetadata.belongsTo(Player, {as: 'player', foreignKey: 'playerId'});
GameMetadata.belongsTo(Game, {as: 'game', foreignKey: 'gameId'});
PlayMetadata.belongsTo(Play, {as: 'play', foreignKey: 'playId'});
GamePlayerMetadata.belongsTo(GamePlayer, {as: 'gamePlayer', foreignKey: 'gamePlayerId'});
GamePlayerMetadata.belongsTo(GamePlayer, {as: 'gamePlayer', foreignKey: 'gamePlayerPk'});
GamePlayerMetadata.belongsTo(Game, {as: 'game', foreignKey: 'gameId'});

Game.hasMany(GamePlayer, {as: 'gamePlayers', foreignKey: 'gameId'});
Game.hasMany(Play, {as: 'plays', foreignKey: 'gameId'});
Player.hasMany(Play, {as: 'plays', foreignKey: 'playerId'});
Player.hasMany(Game, {as: 'games', foreignKey: 'creatorPlayerId'});
GamePlayer.hasMany(Play, {as: 'plays', foreignKey: 'playId'});

GamePlayer.belongsTo(Game, {as: 'game', foreignKey: 'gameId'});
GamePlayer.belongsTo(Player, {as: 'player', foreignKey: 'playerId'});
Play.belongsTo(Game, {as: 'game', foreignKey: 'gameId'});
Play.belongsTo(Player, {as: 'player', foreignKey: 'playerId'});
Play.belongsTo(GamePlayer, {as: 'gamePlayer', foreignKey: 'gamePlayerId'});
Game.belongsTo(Player, {as: 'creatorPlayer', foreignKey: 'creatorPlayerId'});

// This needs to happen before forwarding to index page.
Player.beforeCreate = setPkAndUpdateTimestamp;
Game.beforeCreate = setPkAndUpdateTimestamp;
Play.beforeCreate = setPkAndUpdateTimestamp;
GamePlayer.beforeCreate = setPkAndUpdateTimestamp;
PlayerMetadata.beforeCreate = setPkAndUpdateTimestamp;
GameMetadata.beforeCreate = setPkAndUpdateTimestamp;
PlayMetadata.beforeCreate = setPkAndUpdateTimestamp;
GamePlayerMetadata.beforeCreate = setPkAndUpdateTimestamp;
Player.beforeSave = setPkAndUpdateTimestamp;
Game.beforeSave = setPkAndUpdateTimestamp;
Play.beforeSave = setPkAndUpdateTimestamp;
GamePlayer.beforeSave = setPkAndUpdateTimestamp;
PlayerMetadata.beforeSave = stringifySetPkAndUpdateTimestamp;
GameMetadata.beforeSave = stringifySetPkAndUpdateTimestamp;
PlayMetadata.beforeSave = stringifySetPkAndUpdateTimestamp;
GamePlayerMetadata.beforeSave = stringifySetPkAndUpdateTimestamp;

function stringifySetPkAndUpdateTimestamp(done) {
  this.value = JSON.stringify(this.value);
  setPkAndUpdateTimestamp(done);
}

function setPkAndUpdateTimestamp(done) {
  if(this.pk == DEFAULT_UID) {
    this.pk = uuid.v1();
    this.creationTime = new Date();
  }
  this.lastUpdateTime = new Date();
  done();
}

function findEntityByPk(pk, entity, callback, args) {
  entity.findOne({where: {pk: pk}}, function (err, entity){
    callback(err, entity, args);
  });
}
// schema.automigrate();
exports.Player = Player;
exports.Game = Game;
exports.Play = Play;
exports.GamePlayer = GamePlayer;

exports.PlayerMetadata = PlayerMetadata;
exports.GameMetadata = GameMetadata;
exports.PlayMetadata = PlayMetadata;
exports.GamePlayerMetadata = GamePlayerMetadata;
exports.findEntityByPk = findEntityByPk;